﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Swift;
using Utils;
using TB;

namespace Server {

    public class Game : Port, IFrameDrived {

        public Game() {
            Console.WriteLine ("一个新的游戏正在待命： Game" + this.GetHashCode());
        }

        ~Game() {
            Console.WriteLine ("一个游戏正被终止： Game" + this.GetHashCode());
        }

        public bool Alive = true;

        public int Status {
            get {
                if((conn[0] == null || !conn[0].IsConnected) && (conn[1] == null || !conn[1].IsConnected))
                    return 0;
                return 1;
            }
            set {
                if(value == 0) {
                    for(int i = 0; i < 2; i++) {
                        if(conn[i] != null) {
                            conn[i].Close ();
                            conn[i] = null;
                        }
                    }
                } 
            }
        }

        Connection[] conn = new Connection[2];
        ActorFactory factory;
        int num = 0;
        public int Num {
            get {
                return num;
            }
        }

        int chapter = 1;
        int maxChapter = 7;
        int[,] enemy = new int[4, 2];

        Map map;
        Actor[] player = new Actor[2];

        public void Add(Connection _conn) {
            conn[num++] = _conn;
        }
        CoroutineManager cm;

        public void Start() {

            chapter = 0;

            for(int i=0; i<2; i++) {

                IWriteableBuffer buff = conn[i].BeginSend ("MatchHelper");
                buff.Write ("Match");
                // 匹配状态切换成加载状态，客户端开始切换场景，监听各种事件，准备就绪以后通知服务器
                buff.Write ("Loading");                     
                buff.Write ("Game" + this.GetHashCode ());  // 将游戏组件名通知客户端
                conn[i].End (buff);

            }

            bool[] ready = new bool[] { false, false };
            OnMessage ("Ready", (_conn, data) => {

                if(_conn == conn[0])
                    ready[0] = true;
                else if(_conn == conn[1])
                    ready[1] = true;

                if(ready[0] && ready[1]) {
                    ready[0] = false;
                    ready[1] = false;
                    Load ();
                   
                }

            });

            /*
             * 玩家操作 type：int
             * 解析成二进制。
             * 第一位为 1，表示移动，为 0，表示不移动
             * 第二位、第三位 在有移动时表示方向，没移动时忽略
             * 第四位为 1，表示攻击，为 0，表示不攻击
             */
            OnRequest ("Controller", (_conn, data, buff) => {
                int index = -1;
                int type = data.ReadInt ();

                Console.WriteLine ("收到客户端的type 信息：" + type);

                if(_conn == conn[0]) {
                    index = 0;
                } else if(_conn == conn[1]) {
                    index = 1;
                }

                if(index != -1) {
                    if((type & 1) > 0) {
                        player[index].Move ((type & 6) >> 1, factory);
                    }

                    if((type & 8) > 0) {
                        player[index].Attack (factory, (tag) => {
                            if(tag == "food") {
                                GenFood ();
                            } else if(tag.StartsWith ("enemy")) {
                                int t = (int) (tag[5] - '0');
                                enemy[t, index]++;
                            }
                        });
                    }

                    buff.Write ("OK");
                }
            });
        }

        void GenPlayer(int index, int tid, int x, int y) {

            if(player[index] == null) {
                player[index] = new Actor ();
            }

            if(player[index].Alive == true) {
                int life = player[index].Life;
                player[index] = factory.CreateActor (tid, x, y, 1f, "player" + (index + 1), DIR.UP, player[index].Blood);
                factory.NeedLocomotor (player[index]);
                player[index].Life = life;
                return;
            }

            if(player[index].Life > 0) {
                player[index].Life--;
                int life = player[index].Life;
                player[index] = factory.CreateActor (tid, x, y, 1f, "player"+(index+1), DIR.UP, 1);
                factory.NeedLocomotor (player[index]);
                player[index].Life = life;
            }
        }

        Actor stronghold;

        void Load() {  // 加载资源 
            chapter++;

            factory = new ActorFactory (conn);

            GenPlayer (0, 100, 24, 8);
            GenPlayer (1, 200, 24, 16);

            map = new Map ();
            map.Load (chapter);

            // 创建地图资源，墙、水、草地、滑块
            
            for(int i = 0; i < 26; i++) {
                for(int j = 0; j < 26; j++) {
                    int tid = map.GetXY (i, j);
                    if(tid != 0) {

                        if(tid == 1) {     
                            factory.CreateWoodWall (1001, i, j);
                        } else if(tid == 2) {
                            factory.CreateActor (tid, i, j, 0.5f, "wall");
                        } else if(tid == 3) {
                            factory.CreateActor (tid, i, j, 1f, "water");
                        } else if(tid == 4) {
                            factory.CreateActor (tid, i, j, 1f, "grass");
                        } else if(tid == 5) {
                            factory.CreateActor (tid, i, j, 1f, "slide");
                        } 

                    }
                }
            }

            // 创建基地
            stronghold = factory.CreateActor (10000, 24, 12, 1f, "base");

            cm = GetComponent ("CoroutineManager") as CoroutineManager;

            // 加载敌人
            factory.Add(cm.Start(GenEnemy ()));

        }
    
        void GenFood() {

            int x, y;
            map.RandomPos (out x, out y); 

            int type = RandomUtils.Random(1, 7);
            Actor food = factory.CreateActor (20 + type, x, y, 0.66f, "food");
            food.Type = type;

            Timer timer = GetComponent ("Timer") as Timer;
            timer.AddEvent ("food" + food.GetHashCode (), 0, 1000, (name) => {
                if(food.Alive == false) {
                    timer.RemoveEvent (name);
                    return;
                }
                food.T--;

                if(food.T < 0) {
                    factory.RemoveActor (food);
                    timer.RemoveEvent (name);   
                }
            });

        }

        IEnumerator GenEnemy() {
            int type;
            bool withFood;
            while(factory.Alive && map.Next (out type, out withFood)) {

                int blood = 1;
                if(type == 1)
                    blood = 2;
                else if(type == 3)
                    blood = 4;

                Actor a = factory.CreateActor ((3+type)*100, 0, 0, 1f, "enemy", DIR.UP, blood);
                a.WithFood = true;
                factory.NeedLocomotor (a);

                a.StartAI (factory, (tag) => {
                    if(tag == "player1") {
                        TimerUtils.WaitForMsec (2000, () => {
                            GenPlayer (0, 100, 24, 8);
                        }); 
                    } else if(tag == "player2"){
                        TimerUtils.WaitForMsec (2000, () => {
                            GenPlayer (1, 200, 24, 16);
                        }); 
                    }
                });

                bool wait = true;

                TimerUtils.WaitForMsec (10000, () => {
                    wait = false;
                });

                while(factory.Alive == true && wait == true) {
                    yield return null;
                }
            }

            yield return null;
        }

        public override void Close() {
            if (factory != null) {
                factory.Close();
            }

            for(int i = 0; i < 2; i++) {
                if(conn[i] != null) {
                    conn[i].Close ();
                }    
            }
        }

        void Balance(bool pass) {
           
            for (int i = 0; i < 2; i++) {
                IWriteableBuffer buff = conn[i].BeginSend ("Factory");
                buff.Write ("Balance");
                buff.Write (chapter);
                buff.Write (maxChapter);
                buff.Write (pass ? 1 : 0);
                for (int u = 0; u < 4; u++) {
                    for (int v = 0; v < 2; v++) {
                        buff.Write(enemy[u, v]);
                    }
                }

                conn[i].End(buff);
            }

            factory.Close();

            if(!pass) {
                Status = 0;
            } else if(chapter == maxChapter) {
                Status = 0;
            }
        }

        public void OnTimeElapsed(int te) {

            if( factory != null && factory.Alive == true) {
                for(int i = 0; i < 2; i++) {
                    if(conn[i] != null) {
                        IWriteableBuffer buff = conn[i].BeginSend ("Factory");
                        buff.Write ("Status");
                        buff.Write (1);
                        buff.Write (player[0].Life);
                        buff.Write (player[1].Life);
                        buff.Write (map.GetEnemyNum ());
                        
                        conn[i].End (buff);
                    }
                }

                factory.OnTimeElapsed (te);

                if (stronghold.Alive == false || player[0].Alive == false && player[1].Alive == false) {
                    Balance(false);
                } else if (factory.GetKill() >= 1) {
                    Balance(true);
                }
            }
        }
    }
}
